//##########################################################################
//#                                                                        #
//#                            CLOUDCOMPARE                                #
//#                                                                        #
//#  This program is free software; you can redistribute it and/or modify  #
//#  it under the terms of the GNU General Public License as published by  #
//#  the Free Software Foundation; version 2 of the License.               #
//#                                                                        #
//#  This program is distributed in the hope that it will be useful,       #
//#  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
//#  GNU General Public License for more details.                          #
//#                                                                        #
//#          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
//#                                                                        #
//##########################################################################
//
//*********************** Last revision of this file ***********************
//$Author:: dgm                                                            $
//$Rev:: 1856                                                              $
//$LastChangedDate:: 2011-05-21 21:34:24 +0200 (sam., 21 mai 2011)         $
//**************************************************************************
//

#include "ccCylinder.h"

#include "ccPointCloud.h"
#include "ccNormalVectors.h"

ccCylinder::ccCylinder(PointCoordinateType radius, PointCoordinateType height, ccGLMatrix* transMat /*= 0*/, const char* name /*= "Cylinder"*/)
	: ccGenericPrimitive(name,transMat)
	, m_radius(radius)
	, m_height(height)
{
	setAngularSteps(24);
}

void ccCylinder::setAngularSteps(unsigned steps)
{
	if (steps<4)
		return;

	//vertices
	ccPointCloud* verts = vertices();
	verts->clear();
	verts->reserve(steps*2+2);
	NormsIndexesTableType* normals = new NormsIndexesTableType;
	normals->reserve(steps+2);
	normsType nIndex;
	//2 first points: axis extremities
	PointCoordinateType zMax = m_height*0.5;
	PointCoordinateType zMin = -zMax;
	verts->addPoint(CCVector3(0.0,0.0,zMin));
	nIndex = ccNormalVectors::GetNormIndex(CCVector3(0.0,0.0,-1.0).u);
	normals->addElement(nIndex);
	verts->addPoint(CCVector3(0.0,0.0,zMax));
	nIndex = ccNormalVectors::GetNormIndex(CCVector3(0.0,0.0,1.0).u);
	normals->addElement(nIndex);
	//then, angular sweep
	float angle_rad_step = 2.0*M_PI/(float)steps;
	float angle_rad = 0.0;
	CCVector3 N,P;
	unsigned i;
	for (i=0;i<steps;++i)
	{
		N.x = cos(angle_rad);
		N.y = sin(angle_rad);
		N.z = 0.0;
		nIndex = ccNormalVectors::GetNormIndex(N.u);
		normals->addElement(nIndex);

		P.x = N.x * m_radius;
		P.y = N.y * m_radius;
		P.z = zMin;
		verts->addPoint(P);
		P.z = zMax;
		verts->addPoint(P);

		angle_rad += angle_rad_step;
	}
	setTriNormsTable(normals);
	//DGM FIXME
	addChild(normals,true);
	showTriNorms(true);

	//faces
	assert(m_triIndexes);
	m_triIndexes->clear();

	reserve(steps*4);
	reservePerTriangleNormalIndexes();
	for (i=0;i<steps-1;++i)
	{
		unsigned j1 = 2+2*i; //next point on the circle
		unsigned j2 = j1+1;  //opposite point along the axis
		addTriangle(0,j1+2,j1);
		addTriangleNormalIndexes(0,0,0);
		addTriangle(j1,j1+2,j2);
		addTriangleNormalIndexes(2+i,2+i+1,2+i);
		addTriangle(j2,j1+2,j2+2);
		addTriangleNormalIndexes(2+i,2+i+1,2+i+1);
		addTriangle(1,j2,j2+2);
		addTriangleNormalIndexes(1,1,1);
	}

	//last slice
	unsigned j1 = 2+2*(steps-1);
	unsigned j2 = j1+1;
	addTriangle(0,2,j1);
	addTriangleNormalIndexes(0,0,0);
	addTriangle(j1,2,j2);
	addTriangleNormalIndexes(2+(steps-1),2,2+(steps-1));
	addTriangle(j2,2,3);
	addTriangleNormalIndexes(2+(steps-1),2,2);
	addTriangle(1,j2,3);
	addTriangleNormalIndexes(1,1,1);
}
